#ifndef cpuH
#define cpuH

#include "types.h"
#ifdef SAVESTATES
#include "state.h"
#endif

typedef u8 (*readfuncptr)(void*,u32);
typedef void (*writefuncptr)(void*,u32,u8);

enum addrmodes
	{
	a_none = 0,
	a_zeropage,
	a_absolute,
	a_zeropagex,
	a_absolutex,
	a_absolutey,
	a_relative,
	a_indirectx,
	a_accumulator,
	a_implied,
	a_immediate,
	a_indirecty,
	};

#ifdef NES
#include "ppu.h"
#include "apu.h"
#endif

class Ccpu											//cycle accurate 6502
	{
	protected:
#ifdef NES
		Cppu *ppu;
		Capu *apu;
#endif
   public:
		Ccpu();
		void Reset();								//reset 2a03
		void NMI();									//trigger an nmi
		void IRQ();									//trigger an irq
		void Execute(int ncycles);				//execute some cpu cycles
		void ExecuteOpcode();					//execute one opcode
		void Step();								//step one cycle
		void EatCycles(int n);					//waste n cycles from cpu
#ifdef SAVESTATES
		void SaveState(CState *s);
		void LoadState(CState *s);
#endif
#ifdef NES
		void SetPPU(Cppu *p){ppu = p;}		//set connected ppu
		void SetAPU(Capu *a){apu = a;}		//set connected apu
#endif
		u8 OpRead(u32 addr);						//read from opcode pages
		u8 MemRead(u32 addr);					//read from any memory address
		void MemWrite(u32 addr,u8 data);		//write to any address
   	int GetAddrMode(u8 opcode);			//get address mode of opcode
   	char *GetOpcode(u8 opcode);			//get text opcode name
      int Disassemble(char *buf,u32 addr);//disassemble into buf from addr
   public:
		u32 badopcode;
		u32 extracycle;							//extra cycle flag for addr modes
		u64 cycle;									//current cycle
		u8 opcode;									//current opcode
		u8 opcycle;									//cycle done per opcode
		u32 eaddr;									//effective address
		u8 data;										//some temporary data
		u32 tmp;										//more temp stuff
		u32 pc;										//pc
		u8 a,x,y,f,s;								//registers and flags
		int debug;									//verbosity of messages
		int nmi,irq;
		int nmi_active,irq_active;
		u32 lastread,lastwrite;
		void *user;
#ifdef NES
		u8 r4016reads;
		u8 r4017reads;
		u8 strobe;
#endif
		//todo: rename these and add one for opcodes
		u8 *opromptr[16 * 2];					//opcode page ptrs
		u8 *romptr[16 * 2];						//2k banks
		u8 *ramptr[16 * 2];						//writable ptr's
		readfuncptr opptr[16 * 2];				//opcode read handlers
		readfuncptr readptr[16 * 2];			//read handlers
		writefuncptr writeptr[16 * 2];		//write handlers
   };

#endif
